import java.util.Stack;

/*
 * 1. operates on any primitive function
 * 2. sends any name as an object on the run stack 
 */

public class Rule1 {
	
	Stack<ControlElement> control ;
	Stack<String> stack ;
	Environment environment;
	
	public Rule1(Stack<ControlElement> control, Stack<String> stack, Environment environment){
		this.control = control;
		this.stack = stack;
		this.environment = environment;
	}
	
	/*
	 * if the control is an <identifier> than only it goes for a lookup
	 * else it just passes down to stack
	 */
	void applyRule1() {
		ControlElement controlTop = control.pop();
		if (controlTop.content.contains("<ID:")){
			String returnValue = rule1handleID(controlTop);
			stack.push(returnValue);
		}else{
			stack.push(controlTop.content);
		}
	}

	/*
	 * For PE function, need to pop off the gamma node also 
	 */
	private String rule1handleID(ControlElement controlTop) {
		
		String object = environment.lookup(environment.currentEnv, controlTop.content);
		
		if (object != null && object.contains("<PE:")){
			assert(control.peek().content.equals("gamma")):"Rule 1: Apply PE: gamma node expected to apply a PE function";
			control.pop();
			return applyPrimitiveFunc(controlTop);
		}
		
		if (object != null) {
			return object;
		} else {
			System.out.println("Apply Rule 1: Object not found in the environment");
			System.exit(-1);
			return null;
		}	
	}

	/*
	 * ALl primitive functions have a tag <PE:> with them
	 */
	private String applyPrimitiveFunc(ControlElement controlTop) {
		PEObject object = environment.PELookup(controlTop.content);
		if (object instanceof PrintEnvObject){
			return ((PrintEnvObject) object).apply(stack.pop(), null);
		}else if (object instanceof OrderPE){
			return ((OrderPE) object).apply(stack.pop(), null);
		}else if (object instanceof StemPE){
			return ((StemPE) object).apply(stack.pop(), null);
		}else if (object instanceof SternPE){
			return ((SternPE) object).apply(stack.pop(), null);
		}else if (object instanceof IsintegerPE){
			return ((IsintegerPE) object).apply(stack.pop(), null);
		}else if (object instanceof IsfunctionPE){
			return ((IsfunctionPE) object).apply(stack.pop(), null);
		}else if (object instanceof IstuplePE){
			return ((IstuplePE) object).apply(stack.pop(), null);
		}else if (object instanceof IsdummyPE){
			return ((IsdummyPE) object).apply(stack.pop(), null);
		}else if (object instanceof IsstringPE){
			return ((IsstringPE) object).apply(stack.pop(), null);
		}else if (object instanceof IstruthvaluePE){
			return ((IstruthvaluePE) object).apply(stack.pop(), null);
		}else if (object instanceof ItoSPE){
			return ((ItoSPE) object).apply(stack.pop(), null);
		}else if (object instanceof ConcPE){
			//taking extra "gamma with it"
			control.pop();
			return ((ConcPE) object).apply(stack.pop(), stack.pop());
		}else{
			assert(false):"cant handle anyother primitive functions";
			return null;
		}
		
	}

	/*
	 * pops up print and corresponding gamma node
	 */
	private String applyPrintPrimitive(PrintEnvObject object) {
		String result = object.apply(stack.pop(), null);
		return result;
	}

	/*
	 * Name -> Object
	 */
	boolean checkRule1() {
		String controlTop = control.peek().content;
		if (controlTop.contains("<ID:") | controlTop.contains("<STR:")
				| controlTop.contains("<INT:") | controlTop.equals("<nil>")
				| controlTop.equals("<dummy>") | controlTop.equals("<true>")
				| controlTop.equals("<false>")) {
			return true;

		} else {
			return false;
		}
	}

}
